+++ /dev/null
-#include "config.h"
-
-#include "broadway-buffer.h"
-
-#include <string.h>
-
-/* This code is based on some code from weston with this license:
- *
- * Copyright © 2012 Intel Corporation
- *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the copyright holders not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission. The copyright holders make
- * no representations about the suitability of this software for any
- * purpose. It is provided "as is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-struct entry {
- int count;
- int matches;
- guint32 hash;
- int x, y;
- int index;
-};
-
-struct _BroadwayBuffer {
- guint8 *data;
- struct entry *table;
- int width, height, stride;
- int encoded;
- int block_stride, length, block_count, shift;
- int stats[5];
- int clashes;
-};
-
-static const guint32 prime = 0x1f821e2d;
-static const guint32 end_prime = 0xf907ec81; /* prime^block_size */
-#if 0
-static const guint32 vprime = 0x0137b89d;
-static const guint32 end_vprime = 0xaea9a281; /* vprime^block_size */
-#else
-static const guint32 vprime = 0xf907ec81;
-static const guint32 end_vprime = 0xcdb99001; /* vprime^block_size */
-#endif
-static const guint32 step = 0x0ac93019;
-static const int block_size = 32, block_mask = 31;
-
-static gboolean
-verify_block_match (BroadwayBuffer *buffer, int x, int y,
- BroadwayBuffer *prev, struct entry *entry)
-{
- int i;
- void *old, *match;
- int w1, w2, h1, h2;
-
- w1 = block_size;
- if (x + block_size > buffer->width)
- w1 = buffer->width - x;
-
- h1 = block_size;
- if (y + block_size > buffer->height)
- h1 = buffer->height - y;
-
- w2 = block_size;
- if (entry->x + block_size > prev->width)
- w2 = prev->width - entry->x;
-
- h2 = block_size;
- if (entry->y + block_size > prev->height)
- h2 = prev->height - entry->y;
-
- if (w1 != w2 || h1 != h2)
- return FALSE;
-
- for (i = 0; i < h1; i++)
- {
- match = buffer->data + (y + i) * buffer->stride + x * 4;
- old = prev->data + (entry->y + i) * prev->stride + entry->x * 4;
- if (memcmp (match, old, w1 * 4) != 0)
- {
- buffer->clashes++;
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static void
-insert_block (BroadwayBuffer *buffer, guint32 h, int x, int y)
-{
- struct entry *entry;
- int i;
- guint32 collision = 0;
-
- entry = &buffer->table[h >> buffer->shift];
- for (i = step; entry->count > 0 && entry->hash != h; i += step)
- {
- entry = &buffer->table[(h + i) >> buffer->shift];
- collision++;
- }
-
- entry->hash = h;
- entry->count++;
- entry->x = x;
- entry->y = y;
- entry->index = (buffer->block_stride * y + x) / block_size;
-
- if (collision > G_N_ELEMENTS (buffer->stats) - 1)
- collision = G_N_ELEMENTS (buffer->stats) - 1;
- buffer->stats[collision]++;
-}
-
-static struct entry *
-lookup_block (BroadwayBuffer *prev, guint32 h)
-{
- guint32 i;
- struct entry *entry;
- int shift = prev->shift;
-
- for (i = h;
- entry = &prev->table[i >> shift], entry->count > 0;
- i += step)
- {
- if (entry->hash == h)
- return entry;
- }
-
- return NULL;
-}
-
-struct encoder {
- guint32 color;
- guint32 color_run;
- guint32 delta;
- guint32 delta_run;
- GString *dest;
- int bytes;
-};
-
-/* Encoding:
- *
- * - all 1 pixel colors are encoded literally
- *
- * - We don’t need to support colors with alpha 0 and non-zero
- * color components, as they mean the same on the canvas anyway.
- * So we use these as special codes:
- *
- * - 0x00 00 00 00 : one alpha 0 pixel
- * - 0xaa rr gg bb : one color pixel, alpha > 0
- * - 0x00 1x xx xx : delta 0 run, x is length, (20 bits)
- * - 0x00 2x xx xx 0x xxxx yyyy: block ref, block number x (20 bits) at x, y
- * - 0x00 3x xx xx 0xaarrggbb : solid color run, length x
- * - 0x00 4x xx xx 0xaarrggbb : delta run, length x
- *
- */
-
-static void
-emit (struct encoder *encoder, guint32 symbol)
-{
- g_string_append_len (encoder->dest, (char *)&symbol, sizeof (guint32));
- encoder->bytes += sizeof (guint32);
-}
-
-static void
-encode_run (struct encoder *encoder)
-{
- if (encoder->color_run == 0 && encoder->delta_run == 0)
- return;
-
- if (encoder->color_run >= encoder->delta_run)
- {
- if (encoder->color_run == 1)
- emit (encoder, encoder->color);
- else
- {
- emit (encoder, 0x00300000 | encoder->color_run);
- emit (encoder, encoder->color);
- }
- }
- else
- {
- if (encoder->delta == 0)
- emit(encoder, 0x00100000 | encoder->delta_run);
- else
- {
- emit(encoder, 0x00400000 | encoder->delta_run);
- emit(encoder, encoder->delta);
- }
- }
-}
-
-static void
-encode_pixel (struct encoder *encoder, guint32 color, guint32 prev_color)
-{
- guint32 delta = 0;
- guint32 a, r, g, b;
-
- if (color == prev_color)
- delta = 0;
- else if (prev_color == 0)
- delta = color;
- else
- {
- a = ((color & 0xff000000) - (prev_color & 0xff000000)) & 0xff000000;
- r = ((color & 0x00ff0000) - (prev_color & 0x00ff0000)) & 0x00ff0000;
- g = ((color & 0x0000ff00) - (prev_color & 0x0000ff00)) & 0x0000ff00;
- b = ((color & 0x000000ff) - (prev_color & 0x000000ff)) & 0x000000ff;
-
- delta = a | r | g | b;
- }
-
- if ((encoder->color != color &&
- encoder->color_run > encoder->delta_run) ||
-
- (encoder->delta != delta &&
- encoder->delta_run > encoder->color_run) ||
-
- (encoder->delta != delta && encoder->color != color) ||
-
- (encoder->delta_run == 0xFFFFF || encoder->color_run == 0xFFFFF))
- {
- encode_run (encoder);
-
- encoder->color_run = 1;
- encoder->color = color;
- encoder->delta_run = 1;
- encoder->delta = delta;
- return;
- }
-
- if (encoder->color == color)
- encoder->color_run++;
- else
- {
- encoder->color_run = 1;
- encoder->color = color;
- }
-
- if (encoder->delta == delta)
- encoder->delta_run++;
- else
- {
- encoder->delta_run = 1;
- encoder->delta = delta;
- }
-}
-
-static void
-encoder_flush (struct encoder *encoder)
-{
- encode_run (encoder);
-}
-
-
-static void
-encode_block (struct encoder *encoder, struct entry *entry, int x, int y)
-{
- /* 0x00 2x xx xx 0x xxxx yyyy:
- * block ref, block number x (20 bits) at x, y */
-
- /* FIXME: Maybe don't encode pixels under blocks and just emit
- * blocks at their position within the stream. */
-
- emit (encoder, 0x00200000 | entry->index);
- emit (encoder, (x << 16) | y);
-}
-
-void
-broadway_buffer_destroy (BroadwayBuffer *buffer)
-{
- g_free (buffer->data);
- g_free (buffer->table);
- g_free (buffer);
-}
-
-int
-broadway_buffer_get_width (BroadwayBuffer *buffer)
-{
- return buffer->width;
-}
-
-int
-broadway_buffer_get_height (BroadwayBuffer *buffer)
-{
- return buffer->height;
-}
-
-static void
-unpremultiply_line (void *destp, void *srcp, int width)
-{
- guint32 *src = srcp;
- guint32 *dest = destp;
- guint32 *end = src + width;
- while (src < end)
- {
- guint32 pixel;
- guint8 alpha, r, g, b;
-
- pixel = *src++;
-
- alpha = (pixel & 0xff000000) >> 24;
-
- if (alpha == 0xff)
- *dest++ = pixel;
- else if (alpha == 0)
- *dest++ = 0;
- else
- {
- r = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
- g = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
- b = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
- *dest++ = (guint32)alpha << 24 | (guint32)r << 16 | (guint32)g << 8 | (guint32)b;
- }
- }
-}
-
-BroadwayBuffer *
-broadway_buffer_create (int width, int height, guint8 *data, int stride)
-{
- BroadwayBuffer *buffer;
- int y, bits_required;
-
- buffer = g_new0 (BroadwayBuffer, 1);
- buffer->width = width;
- buffer->stride = width * 4;
- buffer->height = height;
-
- buffer->block_stride = (width + block_size - 1) / block_size;
- buffer->block_count =
- buffer->block_stride * ((height + block_size - 1) / block_size);
- bits_required = g_bit_storage (buffer->block_count * 4);
- buffer->shift = 32 - bits_required;
- buffer->length = 1 << bits_required;
-
- buffer->table = g_malloc0 (buffer->length * sizeof buffer->table[0]);
-
- memset (buffer->stats, 0, sizeof buffer->stats);
- buffer->clashes = 0;
-
- buffer->data = g_malloc (buffer->stride * height);
-
- for (y = 0; y < height; y++)
- unpremultiply_line (buffer->data + y * buffer->stride, data + y * stride, width);
-
- return buffer;
-}
-
-void
-broadway_buffer_encode (BroadwayBuffer *buffer, BroadwayBuffer *prev, GString *dest)
-{
- struct entry *entry;
- int i, j, k;
- int x0, x1, y0, y1;
- guint32 *block_hashes;
- guint32 hash, bottom_hash, h, *line, *bottom, *prev_line;
- int width, height;
- struct encoder encoder = { 0 };
- int *skyline, skyline_pixels;
- int matches;
-
- width = buffer->width;
- height = buffer->height;
- x0 = 0;
- x1 = width;
- y0 = 0;
- y1 = height;
-
- skyline = g_malloc0 ((width + block_size) * sizeof skyline[0]);
-
- block_hashes = g_malloc0 (width * sizeof block_hashes[0]);
-
- matches = 0;
- encoder.dest = dest;
-
- // Calculate the block hashes for the first row
- for (i = y0; i < MIN(y1, y0 + block_size); i++)
- {
- line = (guint32 *)(buffer->data + i * buffer->stride);
- hash = 0;
- for (j = x0; j < MIN(x1, x0 + block_size); j++)
- hash = hash * prime + line[j];
- for (; j < x0 + block_size; j++)
- hash = hash * prime;
-
- for (j = x0; j < x1; j++)
- {
- block_hashes[j] = block_hashes[j] * vprime + hash;
-
- hash = hash * prime - line[j] * end_prime;
- if (j + block_size < width)
- hash += line[j + block_size];
- }
- }
- // Do the last rows if height < block_size
- for (; i < y0 + block_size; i++)
- {
- for (j = x0; j < x1; j++)
- block_hashes[j] = block_hashes[j] * vprime;
- }
-
- for (i = y0; i < y1; i++)
- {
- line = (guint32 *) (buffer->data + i * buffer->stride);
- bottom = (guint32 *) (buffer->data + (i + block_size) * buffer->stride);
- bottom_hash = 0;
- hash = 0;
- skyline_pixels = 0;
-
- if (prev && i < prev->height)
- prev_line = (guint32 *) (prev->data + i * prev->stride);
- else
- prev_line = NULL;
-
- for (j = x0; j < x0 + block_size; j++)
- {
- hash = hash * prime;
- if (j < width)
- hash += line[j];
- if (i + block_size < height)
- {
- bottom_hash = bottom_hash * prime;
- if (j < width)
- bottom_hash += bottom[j];
- }
- if (i < skyline[j])
- skyline_pixels = 0;
- else
- skyline_pixels++;
- }
-
- for (j = x0; j < x1; j++)
- {
- if (i < skyline[j])
- encode_pixel (&encoder, line[j], line[j]);
- else if (prev)
- {
- /* FIXME: Add back overlap exception
- * for consecutive blocks */
-
- h = block_hashes[j];
- entry = lookup_block (prev, h);
- if (entry && entry->count < 2 &&
- skyline_pixels >= block_size &&
- verify_block_match (buffer, j, i, prev, entry) &&
- (entry->x != j || entry->y != i))
- {
- matches++;
- encode_block (&encoder, entry, j, i);
-
- for (k = 0; k < block_size; k++)
- skyline[j + k] = i + block_size;
-
- encode_pixel (&encoder, line[j], line[j]);
- }
- else
- {
- if (prev_line && j < prev->width)
- encode_pixel (&encoder, line[j],
- prev_line[j]);
- else
- encode_pixel (&encoder, line[j], 0);
- }
- }
- else
- encode_pixel (&encoder, line[j], 0);
-
- if (i < skyline[j + block_size])
- skyline_pixels = 0;
- else
- skyline_pixels++;
-
- /* Insert block in hash table if we're on a
- * grid point. */
- if (((i | j) & block_mask) == 0 && !buffer->encoded)
- insert_block (buffer, block_hashes[j], j, i);
-
- /* Update sliding block hash */
- block_hashes[j] =
- block_hashes[j] * vprime + bottom_hash -
- hash * end_vprime;
-
- if (i + block_size < height)
- {
- bottom_hash = bottom_hash * prime - bottom[j] * end_prime;
- if (j + block_size < width)
- bottom_hash += bottom[j + block_size];
- }
- hash = hash * prime - line[j] * end_prime;
- if (j + block_size < width)
- hash += line[j + block_size] ;
- }
- }
-
- encoder_flush (&encoder);
-
-#if 0
- fprintf(stderr, "collision stats:");
- for (i = 0; i < (int) G_N_ELEMENTS(buffer->stats); i++)
- fprintf(stderr, "%c%d", i == 0 ? ' ' : '/', buffer->stats[i]);
- fprintf(stderr, "\n");
-
- fprintf(stderr, "%d / %d blocks (%d%%) matched, %d clashes\n",
- matches, buffer->block_count,
- 100 * matches / buffer->block_count, buffer->clashes);
-
- fprintf(stderr, "output stream %d bytes, raw buffer %d bytes (%d%%)\n",
- encoder.bytes, height * buffer->stride,
- 100 * encoder.bytes / (height * buffer->stride));
-#endif
-
- g_free (skyline);
- g_free (block_hashes);
-
- buffer->encoded = TRUE;
-}
+++ /dev/null
-#ifndef __BROADWAY_BUFFER__
-#define __BROADWAY_BUFFER__
-
-#include "broadway-protocol.h"
-#include <glib-object.h>
-
-typedef struct _BroadwayBuffer BroadwayBuffer;
-
-BroadwayBuffer *broadway_buffer_create (int width,
- int height,
- guint8 *data,
- int stride);
-void broadway_buffer_destroy (BroadwayBuffer *buffer);
-void broadway_buffer_encode (BroadwayBuffer *buffer,
- BroadwayBuffer *prev,
- GString *dest);
-int broadway_buffer_get_width (BroadwayBuffer *buffer);
-int broadway_buffer_get_height (BroadwayBuffer *buffer);
-
-#endif /* __BROADWAY_BUFFER__ */
}
void
-broadway_output_put_buffer (BroadwayOutput *output,
- int id,
- BroadwayBuffer *prev_buffer,
- BroadwayBuffer *buffer)
+broadway_output_window_update (BroadwayOutput *output,
+ int id,
+ guint32 texture)
{
- gsize len;
- int w, h;
- GZlibCompressor *compressor;
- GOutputStream *out, *out_mem;
- GString *encoded;
-
- write_header (output, BROADWAY_OP_PUT_BUFFER);
-
- w = broadway_buffer_get_width (buffer);
- h = broadway_buffer_get_height (buffer);
+ write_header (output, BROADWAY_OP_WINDOW_UPDATE);
append_uint16 (output, id);
- append_uint16 (output, w);
- append_uint16 (output, h);
-
- encoded = g_string_new ("");
- broadway_buffer_encode (buffer, prev_buffer, encoded);
-
- compressor = g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_RAW, -1);
- out_mem = g_memory_output_stream_new_resizable ();
- out = g_converter_output_stream_new (out_mem, G_CONVERTER (compressor));
- g_object_unref (compressor);
-
- if (!g_output_stream_write_all (out, encoded->str, encoded->len,
- NULL, NULL, NULL) ||
- !g_output_stream_close (out, NULL, NULL))
- g_warning ("compression failed");
-
-
- len = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (out_mem));
- append_uint32 (output, len);
-
- g_string_append_len (output->buf, g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (out_mem)), len);
-
- g_string_free (encoded, TRUE);
- g_object_unref (out);
- g_object_unref (out_mem);
+ append_uint32 (output, texture);
}
void
#include <glib.h>
#include <gio/gio.h>
#include "broadway-protocol.h"
-#include "broadway-buffer.h"
typedef struct BroadwayOutput BroadwayOutput;
void broadway_output_set_transient_for (BroadwayOutput *output,
int id,
int parent_id);
-void broadway_output_put_buffer (BroadwayOutput *output,
+void broadway_output_window_update (BroadwayOutput *output,
int id,
- BroadwayBuffer *prev_buffer,
- BroadwayBuffer *buffer);
+ guint32 texture);
void broadway_output_upload_texture (BroadwayOutput *output,
guint32 id,
GBytes *texture);
BROADWAY_OP_REQUEST_AUTH = 'l',
BROADWAY_OP_AUTH_OK = 'L',
BROADWAY_OP_DISCONNECTED = 'D',
- BROADWAY_OP_PUT_BUFFER = 'b',
+ BROADWAY_OP_WINDOW_UPDATE = 'b',
BROADWAY_OP_SET_SHOW_KEYBOARD = 'k',
BROADWAY_OP_UPLOAD_TEXTURE = 't',
BROADWAY_OP_RELEASE_TEXTURE = 'T',
typedef struct {
BroadwayRequestBase base;
guint32 id;
- char name[36];
- guint32 width;
- guint32 height;
+ guint32 texture;
} BroadwayRequestUpdate;
typedef struct {
gboolean is_temp;
gboolean visible;
gint32 transient_for;
-
- BroadwayBuffer *buffer;
- gboolean buffer_synced;
-
- char *cached_surface_name;
- cairo_surface_t *cached_surface;
+ guint32 texture;
};
static void broadway_server_resync_windows (BroadwayServer *server);
}
#endif
-static void *
-map_named_shm (char *name, gsize size)
-{
-#ifdef G_OS_UNIX
-
- int fd;
- void *ptr;
- char *filename = NULL;
-
- fd = shm_open (name, O_RDONLY, 0600);
- if (fd == -1)
- {
- filename = g_build_filename (g_get_tmp_dir (), name, NULL);
- fd = open (filename, O_RDONLY);
- if (fd == -1)
- {
- perror ("Failed to map shm");
- g_free (filename);
-
- return NULL;
- }
- }
-
- ptr = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0);
-
- (void) close (fd);
-
- if (filename)
- {
- unlink (filename);
- g_free (filename);
- }
- else
- shm_unlink (name);
-
- return ptr;
-
-#elif defined(G_OS_WIN32)
-
- int fd;
- void *ptr;
- char *shmpath;
- void *map = ((void *)-1);
-
- if (*name == '/')
- ++name;
- shmpath = g_build_filename (g_get_tmp_dir (), name, NULL);
-
- fd = open(shmpath, O_RDONLY, 0600);
- if (fd == -1)
- {
- g_free (shmpath);
- perror ("Failed to shm_open");
- return NULL;
- }
-
- if (size == 0)
- ptr = map;
- else
- {
- HANDLE h, fm;
- h = (HANDLE)_get_osfhandle (fd);
- fm = CreateFileMapping (h, NULL, PAGE_READONLY, 0, (DWORD)size, NULL);
- ptr = MapViewOfFile (fm, FILE_MAP_READ, 0, 0, (size_t)size);
- CloseHandle (fm);
- }
-
- (void) close(fd);
-
- remove (shmpath);
- g_free (shmpath);
-
- return ptr;
-
-#else
-#error "No shm mapping supported"
-
- return NULL;
-#endif
-}
-
static const char *
parse_line (const char *line, const char *key)
{
g_hash_table_remove (server->id_ht,
GINT_TO_POINTER (id));
- g_free (window->cached_surface_name);
- if (window->cached_surface != NULL)
- cairo_surface_destroy (window->cached_surface);
-
g_free (window);
}
}
}
void
-broadway_server_window_update (BroadwayServer *server,
- gint id,
- cairo_surface_t *surface)
+broadway_server_window_update (BroadwayServer *server,
+ gint id,
+ guint32 texture)
{
BroadwayWindow *window;
- BroadwayBuffer *buffer;
-
- if (surface == NULL)
- return;
window = g_hash_table_lookup (server->id_ht,
GINT_TO_POINTER (id));
if (window == NULL)
return;
- g_assert (window->width == cairo_image_surface_get_width (surface));
- g_assert (window->height == cairo_image_surface_get_height (surface));
-
- buffer = broadway_buffer_create (window->width, window->height,
- cairo_image_surface_get_data (surface),
- cairo_image_surface_get_stride (surface));
+ window->texture = texture;
if (server->output != NULL)
- {
- window->buffer_synced = TRUE;
- broadway_output_put_buffer (server->output, window->id,
- window->buffer, buffer);
- }
-
- if (window->buffer)
- broadway_buffer_destroy (window->buffer);
-
- window->buffer = buffer;
+ broadway_output_window_update (server->output, window->id,
+ window->texture);
}
guint32
return serial;
}
-static const cairo_user_data_key_t shm_cairo_key;
-
-typedef struct {
- void *data;
- gsize data_size;
-} ShmSurfaceData;
-
-static void
-shm_data_unmap (void *_data)
-{
- ShmSurfaceData *data = _data;
-#ifdef G_OS_UNIX
- munmap (data->data, data->data_size);
-#elif defined(G_OS_WIN32)
- UnmapViewOfFile (data->data);
-#endif
- g_free (data);
-}
-
-cairo_surface_t *
-broadway_server_open_surface (BroadwayServer *server,
- guint32 id,
- char *name,
- int width,
- int height)
-{
- BroadwayWindow *window;
- ShmSurfaceData *data;
- cairo_surface_t *surface;
- gsize size;
- void *ptr;
-
- window = g_hash_table_lookup (server->id_ht,
- GINT_TO_POINTER (id));
- if (window == NULL)
- return NULL;
-
- if (window->cached_surface_name != NULL &&
- strcmp (name, window->cached_surface_name) == 0)
- return cairo_surface_reference (window->cached_surface);
-
- size = width * height * sizeof (guint32);
-
- ptr = map_named_shm (name, size);
-
- if (ptr == NULL)
- return NULL;
-
- data = g_new0 (ShmSurfaceData, 1);
-
- data->data = ptr;
- data->data_size = size;
-
- surface = cairo_image_surface_create_for_data ((guchar *)data->data,
- CAIRO_FORMAT_ARGB32,
- width, height,
- width * sizeof (guint32));
- g_assert (surface != NULL);
-
- cairo_surface_set_user_data (surface, &shm_cairo_key,
- data, shm_data_unmap);
-
- g_free (window->cached_surface_name);
- window->cached_surface_name = g_strdup (name);
-
- if (window->cached_surface != NULL)
- cairo_surface_destroy (window->cached_surface);
- window->cached_surface = cairo_surface_reference (surface);
-
- return surface;
-}
-
guint32
broadway_server_new_window (BroadwayServer *server,
int x,
if (window->id == 0)
continue; /* Skip root */
- window->buffer_synced = FALSE;
broadway_output_new_surface (server->output,
window->id,
window->x,
continue; /* Skip root */
if (window->transient_for != -1)
- broadway_output_set_transient_for (server->output, window->id, window->transient_for);
+ broadway_output_set_transient_for (server->output, window->id,
+ window->transient_for);
+
+ broadway_output_window_update (server->output, window->id,
+ window->texture);
+
if (window->visible)
- {
- broadway_output_show_surface (server->output, window->id);
-
- if (window->buffer != NULL)
- {
- window->buffer_synced = TRUE;
- broadway_output_put_buffer (server->output, window->id,
- NULL, window->buffer);
- }
- }
+ broadway_output_show_surface (server->output, window->id);
}
if (server->show_keyboard)
int height);
void broadway_server_window_update (BroadwayServer *server,
gint id,
- cairo_surface_t *surface);
+ guint32 texture);
gboolean broadway_server_window_move_resize (BroadwayServer *server,
gint id,
gboolean with_move,
int height);
void broadway_server_focus_window (BroadwayServer *server,
gint new_focused_window);
-cairo_surface_t * broadway_server_open_surface (BroadwayServer *server,
- guint32 id,
- char *name,
- int width,
- int height);
#endif /* __BROADWAY_SERVER__ */
log(callstack[i]);
}
-function resizeCanvas(canvas, w, h)
-{
- /* Canvas resize clears the data, so we need to save it first */
- var tmpCanvas = canvas.ownerDocument.createElement("canvas");
- tmpCanvas.width = canvas.width;
- tmpCanvas.height = canvas.height;
- var tmpContext = tmpCanvas.getContext("2d");
- tmpContext.globalCompositeOperation = "copy";
- tmpContext.drawImage(canvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
-
- canvas.width = w;
- canvas.height = h;
-
- var context = canvas.getContext("2d");
-
- context.globalCompositeOperation = "copy";
- context.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height);
-}
-
var grab = new Object();
grab.window = null;
grab.ownerEvents = false;
surface.visible = false;
surface.imageData = null;
- var canvas = document.createElement("canvas");
- canvas.width = width;
- canvas.height = height;
- canvas.surface = surface;
- surface.canvas = canvas;
+ var image = new Image();
+ image.width = width;
+ image.height = height;
+ image.surface = surface;
+ surface.image = image;
var toplevelElement;
- toplevelElement = canvas;
- document.body.appendChild(canvas);
+ toplevelElement = image;
+ document.body.appendChild(image);
surface.toplevelElement = toplevelElement;
toplevelElement.style["position"] = "absolute";
var i = stackingOrder.indexOf(surface);
if (i >= 0)
stackingOrder.splice(i, 1);
- var canvas = surface.canvas;
- canvas.parentNode.removeChild(canvas);
+ var image = surface.image;
+ image.parentNode.removeChild(image);
delete surfaces[id];
}
surface.height = h;
}
- if (has_size)
- resizeCanvas(surface.canvas, w, h);
+ if (has_size) {
+ surface.image.width = w;
+ surface.image.height = h;
+ }
if (surface.visible) {
if (has_pos) {
var xOffset = surface.x;
var yOffset = surface.y;
- var element = surface.canvas;
+ var element = surface.image;
element.style["left"] = xOffset + "px";
element.style["top"] = yOffset + "px";
return imageData;
}
-function cmdPutBuffer(id, w, h, compressed)
+function cmdWindowUpdate(id, texture_id)
{
var surface = surfaces[id];
- var context = surface.canvas.getContext("2d");
-
- var inflate = new Zlib.RawInflate(compressed);
- var data = inflate.decompress();
-
- var imageData = decodeBuffer (context, surface.imageData, w, h, data, debugDecoding);
- context.putImageData(imageData, 0, 0);
-
- if (debugDecoding)
- imageData = decodeBuffer (context, surface.imageData, w, h, data, false);
+ var texture_url = textures[texture];
- surface.imageData = imageData;
+ surface.image.src = texture_url;
}
function cmdUploadTexture(id, data)
cmdLowerSurface(id);
break;
- case 'b': // Put image buffer
+ case 'b': // Update window
id = cmd.get_16();
- w = cmd.get_16();
- h = cmd.get_16();
- var data = cmd.get_data();
- cmdPutBuffer(id, w, h, data);
+ texture = cmd.get_32();
+ cmdWindowUpdate(id, texture);
break;
case 't': // Upload texture
BroadwayReplyQueryMouse reply_query_mouse;
BroadwayReplyGrabPointer reply_grab_pointer;
BroadwayReplyUngrabPointer reply_ungrab_pointer;
- cairo_surface_t *surface;
guint32 before_serial, now_serial;
guint32 global_id;
int fd;
request->set_transient_for.parent);
break;
case BROADWAY_REQUEST_UPDATE:
- surface = broadway_server_open_surface (server,
- request->update.id,
- request->update.name,
- request->update.width,
- request->update.height);
- if (surface != NULL)
- {
- broadway_server_window_update (server,
- request->update.id,
- surface);
- cairo_surface_destroy (surface);
- }
+ global_id = GPOINTER_TO_INT (g_hash_table_lookup (client->textures,
+ GINT_TO_POINTER (request->update.texture)));
+ broadway_server_window_update (server,
+ request->update.id,
+ global_id);
break;
case BROADWAY_REQUEST_UPLOAD_TEXTURE:
if (client->fds == NULL)
BROADWAY_REQUEST_SET_TRANSIENT_FOR);
}
-static void *
-map_named_shm (char *name, gsize size, gboolean *is_shm)
-{
-#ifdef G_OS_UNIX
-
- char *filename = NULL;
- int fd;
- void *ptr;
- int res;
-
- fd = shm_open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
- if (fd == -1)
- {
- if (errno == EEXIST)
- return NULL;
-
- filename = g_build_filename (g_get_tmp_dir (), name, NULL);
-
- fd = open (filename, O_RDWR | O_CREAT | O_EXCL, 0600);
- g_free (filename);
- if (fd == -1)
- {
- if (errno != EEXIST)
- g_error ("Unable to allocate shared mem for window");
- return NULL;
- }
- else
- *is_shm = FALSE;
- }
- else
- *is_shm = TRUE;
-
- res = ftruncate (fd, size);
- g_assert (res != -1);
-
-#ifdef HAVE_POSIX_FALLOCATE
- res = posix_fallocate (fd, 0, size);
- if (res != 0 && errno == ENOSPC)
- {
- if (filename)
- unlink (filename);
- else
- shm_unlink (name);
- g_error ("Not enough shared memory for window surface");
- }
-#endif
-
- ptr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-
- (void) close(fd);
-
- return ptr;
-
-#elif defined(G_OS_WIN32)
-
- int fd;
- void *ptr;
- char *shmpath;
- void *map = ((void *)-1);
- int res;
-
- if (*name == '/')
- ++name;
- shmpath = g_build_filename (g_get_tmp_dir (), name, NULL);
-
- fd = open(shmpath, O_RDWR|O_CREAT|O_EXCL, 0600);
- g_free (shmpath);
- if (fd == -1)
- {
- if (errno != EEXIST)
- g_error ("Unable to allocate shared mem for window");
- return NULL;
- }
-
- *is_shm = TRUE;
- res = ftruncate (fd, size);
- g_assert (res != -1);
-
- if (size == 0)
- ptr = map;
- else
- {
- HANDLE h, fm;
- h = (HANDLE)_get_osfhandle (fd);
- fm = CreateFileMapping (h, NULL, PAGE_READWRITE, 0, (DWORD)size, NULL);
- ptr = MapViewOfFile (fm, FILE_MAP_WRITE, 0, 0, (size_t)size);
- CloseHandle (fm);
- }
-
- (void) close(fd);
-
- return ptr;
-
-#else
-#error "No shm mapping supported"
-
- return NULL;
-#endif
-}
-
-static char
-make_valid_fs_char (char c)
-{
- char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890";
-
- return chars[c % (sizeof (chars) - 1)];
-}
-
-/* name must have at least space for 34 bytes */
-static gpointer
-create_random_shm (char *name, gsize size, gboolean *is_shm)
-{
- guint32 r;
- int i, o;
- gpointer ptr;
-
- while (TRUE)
- {
- o = 0;
- name[o++] = '/';
- name[o++] = 'b';
- name[o++] = 'd';
- name[o++] = 'w';
- name[o++] = '-';
- for (i = 0; i < 32/4 - 1; i++)
- {
- r = g_random_int ();
- name[o++] = make_valid_fs_char ((r >> 0) & 0xff);
- name[o++] = make_valid_fs_char ((r >> 8) & 0xff);
- name[o++] = make_valid_fs_char ((r >> 16) & 0xff);
- name[o++] = make_valid_fs_char ((r >> 24) & 0xff);
- }
- name[o++] = 0;
-
- ptr = map_named_shm (name, size, is_shm);
- if (ptr)
- return ptr;
- }
-}
-
-static const cairo_user_data_key_t gdk_broadway_shm_cairo_key;
-
-typedef struct {
- char name[36];
- void *data;
- gsize data_size;
- gboolean is_shm;
-} BroadwayShmSurfaceData;
-
-static void
-shm_data_destroy (void *_data)
-{
- BroadwayShmSurfaceData *data = _data;
-
-#ifdef G_OS_UNIX
-
- munmap (data->data, data->data_size);
- if (data->is_shm)
- shm_unlink (data->name);
- else
- {
- char *filename = g_build_filename (g_get_tmp_dir (), data->name, NULL);
- unlink (filename);
- g_free (filename);
- }
-
-#elif defined(G_OS_WIN32)
-
- char *name = data->name;
- char *shmpath;
-
- if (*name == '/')
- ++name;
-
- shmpath = g_build_filename (g_get_tmp_dir (), name, NULL);
- UnmapViewOfFile (data->data);
- remove (shmpath);
- g_free (shmpath);
-
-#endif
-
- g_free (data);
-}
-
-cairo_surface_t *
-_gdk_broadway_server_create_surface (int width,
- int height)
-{
- BroadwayShmSurfaceData *data;
- cairo_surface_t *surface;
-
- data = g_new (BroadwayShmSurfaceData, 1);
- data->data_size = width * height * sizeof (guint32);
- data->data = create_random_shm (data->name, data->data_size, &data->is_shm);
-
- surface = cairo_image_surface_create_for_data ((guchar *)data->data,
- CAIRO_FORMAT_ARGB32, width, height, width * sizeof (guint32));
- g_assert (surface != NULL);
-
- cairo_surface_set_user_data (surface, &gdk_broadway_shm_cairo_key,
- data, shm_data_destroy);
-
- return surface;
-}
-
void
_gdk_broadway_server_window_update (GdkBroadwayServer *server,
gint id,
- cairo_surface_t *surface)
+ guint32 texture)
{
BroadwayRequestUpdate msg;
- BroadwayShmSurfaceData *data;
-
- if (surface == NULL)
- return;
-
- data = cairo_surface_get_user_data (surface, &gdk_broadway_shm_cairo_key);
- g_assert (data != NULL);
msg.id = id;
- memcpy (msg.name, data->name, 36);
- msg.width = cairo_image_surface_get_width (surface);
- msg.height = cairo_image_surface_get_height (surface);
+ msg.texture = texture;
gdk_broadway_server_send_message (server, msg,
BROADWAY_REQUEST_UPDATE);
GdkTexture *texture);
void gdk_broadway_server_release_texture (GdkBroadwayServer *server,
guint32 id);
-cairo_surface_t *_gdk_broadway_server_create_surface (int width,
- int height);
void _gdk_broadway_server_window_update (GdkBroadwayServer *server,
gint id,
- cairo_surface_t *surface);
+ guint32 texture);
gboolean _gdk_broadway_server_window_move_resize (GdkBroadwayServer *server,
gint id,
gboolean with_move,
#include "gdkinternals.h"
#include "gdkdeviceprivate.h"
#include "gdkdevicemanager-broadway.h"
+#include <gdk/gdktextureprivate.h>
#include <glib.h>
#include <glib/gprintf.h>
#include "gdkinternals.h"
#include "gdkdeviceprivate.h"
#include "gdkeventsource.h"
+#include <gdk/gdktextureprivate.h>
#include <stdlib.h>
#include <stdio.h>
if (impl->dirty)
{
+ GdkTexture *texture;
+ guint32 texture_id;
+
impl->dirty = FALSE;
updated_surface = TRUE;
+
+ if (impl->texture_id)
+ gdk_broadway_server_release_texture (display->server, impl->texture_id);
+ impl->texture_id = 0;
+
+ texture = gdk_texture_new_for_surface (impl->surface);
+ texture_id = gdk_broadway_server_upload_texture (display->server, texture);
+ g_object_unref (texture);
+
+ impl->texture_id = texture_id;
+
_gdk_broadway_server_window_update (display->server,
impl->id,
- impl->surface);
+ texture_id);
+
}
}
{
cairo_surface_destroy (impl->surface);
- impl->surface = _gdk_broadway_server_create_surface (gdk_window_get_width (impl->wrapper),
- gdk_window_get_height (impl->wrapper));
+ impl->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ gdk_window_get_width (impl->wrapper),
+ gdk_window_get_height (impl->wrapper));
}
if (impl->ref_surface)
/* Create actual backing store if missing */
if (!impl->surface)
- impl->surface = _gdk_broadway_server_create_surface (w, h);
+ impl->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
/* Create a destroyable surface referencing the real one */
if (!impl->ref_surface)
g_hash_table_remove (broadway_display->id_ht, GINT_TO_POINTER (impl->id));
_gdk_broadway_server_destroy_window (broadway_display->server, impl->id);
+ if (impl->texture_id)
+ gdk_broadway_server_release_texture (broadway_display->server, impl->texture_id);
+
}
/* This function is called when the XWindow is really gone.
GdkCursor *cursor;
int id;
+ int texture_id;
gboolean visible;
gboolean maximized;
gdk_broadway_sources = files([
- 'broadway-buffer.c',
'broadway-output.c',
'broadway-server.c',
'broadwayd.c',
executable('gtk4-broadwayd',
clienthtml_h, broadwayjs_h,
- 'broadwayd.c', 'broadway-server.c', 'broadway-buffer.c', 'broadway-output.c',
+ 'broadwayd.c', 'broadway-server.c', 'broadway-output.c',
include_directories: [confinc, gdkinc],
c_args: ['-DGDK_COMPILATION', '-DG_LOG_DOMAIN="Gdk"', ],
dependencies : [broadwayd_syslib, gdk_deps],